/*
 * /trunk/sync.c
 * 
 * Harry Wei <harryxiyou@gmail.com> 2012 5 14
 * Codes taken from Teacher Chen's Linux Os book
 */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/semaphore.h>
#include <linux/mutex.h>
#include <linux/sched.h>
#include <asm/atomic.h>
#include <linux/delay.h>
#include <linux/kthread.h>

#define PRODUCT_NUMS	(10)

static struct semaphore sem_producer;
static struct semaphore sem_consumer;
static char product[12];
static atomic_t num;
static int producer(void *product);
static int consumer(void *product);
static int id = 1;
static int consume_num = 1;

/*producer's thread */
static int producer(void *p) {
	char *product = (char *)p;
	int i = 0;
	
	atomic_inc(&num);
	printk(KERN_DEBUG "producer [%d] start ...\n", current->pid);
	for (i = 0; i < PRODUCT_NUMS; i++) {
		down(&sem_producer);
		snprintf(product, 12, "2012-5-14-%d", id++);
		printk(KERN_DEBUG "producer [%d] produce %s\n", current->pid, product);
		up(&sem_consumer);
	}
	printk(KERN_DEBUG "producer [%d] exit...\n", current->pid);
	return 0;
}

/*consumer threrad*/
static int consumer(void *p) {
	char *product = (char *)p;

	printk(KERN_DEBUG "consumer [%d] start ...\n", current->pid);
	for ( ; ; ) {
		msleep(100);
		down_interruptible(&sem_consumer);
		if (consume_num >= PRODUCT_NUMS * atomic_read(&num)) {
			break;
		}
		printk(KERN_DEBUG "consumer [%d] consume %s\n", current->pid, product);
		consume_num++;
		memset(product, '\0', 12);
		up(&sem_producer);
	}
	printk(KERN_DEBUG "consumer [%d] exit\n", current->pid);
	return 0;
}

/* Just a use case */
static int procon_init(void) {
	printk(KERN_INFO "show producer and consumer\n");
	sema_init(&sem_producer, 1);
	sema_init(&sem_consumer, 0);
	atomic_set(&num, 0);
	kernel_thread(producer, product, CLONE_KERNEL);
	kernel_thread(consumer, product, CLONE_KERNEL);
	return 0;
}

static void procon_exit(void) {
	printk(KERN_INFO "exit producer and consumer\n");
}

module_init(procon_init);
module_exit(procon_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Harry Wei <harryxiyou@gmail.com>");
MODULE_DESCRIPTION("sync from Teacher Chen's book -- Linux OS");
